1. Field of the Invention
The field of the invention is data processing, or, more specifically, methods, systems, and products for administration of locks for critical sections of computer programs in a computer that supports a multiplicity of logical partitions.
2. Description of Related Art
A thread is a unit of software execution on a multi-threaded computer. That is, a thread is an executable entity of work in a computer system. A thread can be viewed as a separate stream of executable computer program instructions. On such a computer, software programs are executed in units of execution called ‘processes’ that include all the processor registers, code segment and offset registers, data segment and offset registers, stack segment and offset registers, flag registers, instruction pointer registers, program counters, and so on, needed for execution of software programs. For efficiency, ‘processes’ are organized further as threads, where each thread of a process individually possesses all the attributes needed for execution except that a thread shares memory among all the other threads of a process, thereby reducing the overhead of operating system switches from thread to thread (‘context switches’).
Threads of a process share the same memory space and are capable of reading and writing to the same memory addresses. Moreover, a thread reading a memory address may suffer an interrupt between any two computer program instructions, and there is no guarantee that a processor will regain run status before another thread writes to the same memory address. Such a situation is called a ‘race condition.’ A race condition can occur when more than one thread can simultaneously access shared memory, and the threads can both read and modify the data in memory. A common way to prevent race conditions is called ‘mutual exclusion’ or ‘mutex.’ In mutual exclusions, portions of code where shared data are read or modified are defined as ‘critical sections,’ and some mechanism is implemented to guarantee that two threads will never be in a critical section for the same shared data at the same time.
A mechanism that guarantees that two threads will never be in a critical section for the same shared data at the same time is referred to in this specification as a ‘lock.’ Examples of locks include Unix semaphores, monitor classes in C++, and synchronized methods in Java. A thread that requests exclusive access to a critical section for shared data is said to request a lock; requesting a lock is typically implemented with a system call which, if the lock is not immediately available, places the requesting thread in wait state until the lock becomes available. A thread that has exclusive access to a critical section for shared data is said to hold the lock.
Locks are amenable to convoy effects. Only one thread at a time can gain possession of a lock. A convoy occurs when a number of threads request access to the same lock. All requesting threads may experience context switches from run state to wait state. They may leave wait state, return to ready state, compete for possession of a processor, again request the lock, and, if it is not available, again return to wait state—to start the whole process all over again. The traditional remedy is to minimize the size of critical sections of computer program instructions, so that a lock-holder only retains the lock for the minimum amount of time necessary to carry out the pertinent data processing. This is not a complete solution, however, and, when convoy effects occur, they are particularly detrimental to overall computer system performance.
A logical partition (‘LPAR’) is a set of data structures and services that enables distribution of computer resources within a single computer to make the computer function as if it were two or more independent computers. A hypervisor is a layer of system software that runs under operating systems in logical partitions to schedule virtual processors on physical processors. A virtual processor is a subsystem that implements assignment of processor time to a logical partition. A shared pool of physical processors supports the assignment of partial physical processors (in time slices) to a logical partition. Such partial physical processors shared in time slices are referred to as ‘virtual processors.’ A thread is said to run on a virtual processor when it is running on the virtual processor's time slice. Sub-processor partitions time-share a physical processor among a set of virtual processors, in a manner that is invisible to an operating system running in a logical partition. Unlike multiprogramming within the operating system where a thread can remain in control of the physical processor by running in interrupt-disabled mode, in subprocessor partitions, the thread is still pre-empted by the hypervisor at the end of its virtual processor's time-slice, in order to make the physical processor available to a different virtual processor.
Thus, in a sub-processor partition, if a thread were to acquire a lock (even under interrupt-disabled conditions), there is no guarantee that the lock will be released before the thread gives up control of the physical processor. This often leads to long delays between lock acquisition and release, because the lock can only be released after the thread regains control of a physical processor in order to complete execution of its critical section. These long delays exacerbate lock contention within a partition, because other virtual processors vying for the lock are forced to wait until the lock-holding virtual processor regains control of a physical processor and releases the lock.